/**
 * @author DELL
 * @createDate 2016/11/15 16:30
 * @copyright 广州市生物制品有限公司
 * @description 未经本公司许可，不得以任何方式复制或使用本程序任何部分
 */
package com.lzw.entity;

import com.lzw.command.CreateAccountCommand;
import com.lzw.command.CreditAccountCommand;
import com.lzw.command.DebitAccountCommand;
import com.lzw.event.AccountCreatedEvent;
import com.lzw.event.AccountCreditedEvent;
import com.lzw.event.AccountDebitedEvent;
import org.axonframework.commandhandling.annotation.CommandHandler;
import org.axonframework.eventsourcing.annotation.AbstractAnnotatedAggregateRoot;
import org.axonframework.eventsourcing.annotation.AggregateIdentifier;
import org.axonframework.eventsourcing.annotation.EventSourcingHandler;

/**
 * 类功能描述: TODO
 *
 * @author 12360
 * @version 1.0
 * @createDate Nov 19, 2015 11:16:44 AM
 */
public class Account extends AbstractAnnotatedAggregateRoot {

    @AggregateIdentifier
    private String accountNo;

    private Double balance;

    public Account() {
    }

    @CommandHandler
    public Account(CreateAccountCommand createAccountCommand) {
        apply(new AccountCreatedEvent(createAccountCommand.getAccount()));
    }

    @CommandHandler
    public void debit(DebitAccountCommand debitAccountCommand) {
        if (Double.compare(debitAccountCommand.getAmount(), 0.0d) > 0 && this.balance - debitAccountCommand.getAmount() > -1) {
            apply(new AccountDebitedEvent(this.accountNo, debitAccountCommand.getAmount(), this.balance));
        } else {
            throw new IllegalArgumentException("Cannot debit with the amount");
        }

    }

    @CommandHandler
    public void credit(CreditAccountCommand creditAccountCommand) {
        if (Double.compare(creditAccountCommand.getAmount(), 0.0d) > 0 &&
                Double.compare(creditAccountCommand.getAmount(), 1000000) < 0) {
            apply(new AccountCreditedEvent(this.accountNo, creditAccountCommand.getAmount(), this.balance));
        } else {
            throw new IllegalArgumentException("Cannot credit with the amount");
        }
    }

    @EventSourcingHandler
    public void applyAccountCreation(AccountCreatedEvent event) {
        this.accountNo = event.getAccountNo();
        this.balance = 0.0d;
    }

    @EventSourcingHandler
    private void applyDebit(AccountDebitedEvent event) {
        this.balance -= event.getAmountDebited();
    }

    @EventSourcingHandler
    private void applyCredit(AccountCreditedEvent event) {
        this.balance += event.getAmountCredited();
    }

    public String getAccountNo() {
        return accountNo;
    }

    /**
     * Returns the identifier of this aggregate.
     *
     * @return the identifier of this aggregate
     */


    public Double getBalance() {
        return balance;
    }
}
